from fastapi import APIRouter, HTTPException, Depends, BackgroundTasks
from pydantic import BaseModel, Field
from typing import Optional, Dict, Any
import logging
import json
from datetime import datetime

from db_manager import DatabaseManager
from three_d_effect_evaluation.model_evaluator import ModelEvaluator
from three_d_effect_evaluation.model_processing_service import ModelProcessingService

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# 创建路由器
router = APIRouter(prefix="/api/v2/evaluation", tags=["3D模型评估"])

# 初始化数据库管理器和评估器
db_manager = DatabaseManager()
model_evaluator = ModelEvaluator()

# 请求模型定义
class EvaluateModelRequest(BaseModel):
    model_3d_url: str = Field(..., description="3D模型URL")
    prompt: str = Field(..., description="用户提示词")
    user_id: int = Field(..., description="用户ID")
    reference_image: Optional[str] = Field(None, description="参考图片URL")

# 通用响应模型
def create_response(code: int, msg: str = "", data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
    """
    创建标准格式的响应
    
    Args:
        code: 状态码，1代表成功，0代表失败
        msg: 消息描述
        data: 业务数据
        
    Returns:
        标准格式的响应字典
    """
    return {
        "code": code,
        "msg": msg,
        "data": data or {}
    }

# 3D模型评估接口（同步）
@router.post("/evaluate-model", tags=["3D模型评估"])
def evaluate_model(request: EvaluateModelRequest):
    """
    评估3D模型效果
    
    - **model_3d_url**: 3D模型的URL地址
    - **prompt**: 用户原始提示词
    - **user_id**: 用户ID
    - **reference_image**: 可选的参考图片URL
    
    返回包含评估报告的响应，格式为标准的业务响应格式
    """
    try:
        if not request.model_3d_url or request.model_3d_url.strip() == "":
            return create_response(code=0, msg="3D模型URL不能为空")
        
        if not request.prompt or request.prompt.strip() == "":
            return create_response(code=0, msg="用户提示词不能为空")
        
        logger.info(f"开始评估3D模型，用户ID: {request.user_id}, 模型URL: {request.model_3d_url}")
        
        # 执行评估
        evaluation_result = model_evaluator.evaluate(
            model_url=request.model_3d_url,
            prompt=request.prompt,
            user_id=request.user_id,
            reference_image=request.reference_image
        )
        
        # 将评估报告保存到数据库
        report_id = db_manager.insert_evaluation_report(
            model_3d_url=evaluation_result["model_3d_url"],
            user_id=evaluation_result["user_id"],
            title=evaluation_result["title"],
            markdown_report=evaluation_result["markdown_report"],
            screenshot=evaluation_result.get("screenshot")
        )
        
        # 构建返回数据
        report_data = {
            "title": evaluation_result["title"],
            "markdown_report": evaluation_result["markdown_report"]
        }
        
        logger.info(f"3D模型评估完成，报告ID: {report_id}")
        
        return create_response(
            code=1,
            msg="3D模型评估成功",
            data=report_data
        )
        
    except Exception as e:
        logger.error(f"3D模型评估过程中发生错误: {str(e)}")
        return create_response(
            code=0,
            msg=f"评估失败: {str(e)}",
            data={}
        )

# 3D模型评估接口（异步）
@router.post("/evaluate-model-async", tags=["3D模型评估"])
def evaluate_model_async(
    request: EvaluateModelRequest,
    background_tasks: BackgroundTasks
):
    """
    异步评估3D模型效果（通过后台任务执行）
    
    - **model_3d_url**: 3D模型的URL地址
    - **prompt**: 用户原始提示词
    - **user_id**: 用户ID
    - **reference_image**: 可选的参考图片URL
    
    返回任务提交成功的响应，评估将在后台进行
    """
    try:
        if not request.model_3d_url or request.model_3d_url.strip() == "":
            return create_response(code=0, msg="3D模型URL不能为空")
        
        if not request.prompt or request.prompt.strip() == "":
            return create_response(code=0, msg="用户提示词不能为空")
        
        logger.info(f"提交3D模型异步评估任务，用户ID: {request.user_id}")
        
        # 定义回调函数
        def on_evaluation_complete(evaluation_result):
            try:
                # 将评估报告保存到数据库
                report_id = db_manager.insert_evaluation_report(
                    model_3d_url=evaluation_result["model_3d_url"],
                    user_id=evaluation_result["user_id"],
                    title=evaluation_result["title"],
                    markdown_report=evaluation_result["markdown_report"],
                    screenshot=evaluation_result.get("screenshot")
                )
                
                logger.info(f"异步评估完成并保存报告，报告ID: {report_id}")
                
                # 这里可以添加通知逻辑，如WebSocket推送等
                # 用于将"completed"状态推送给浏览器
                
            except Exception as e:
                logger.error(f"保存异步评估报告失败: {str(e)}")
        
        # 添加到后台任务
        background_tasks.add_task(
            model_evaluator.evaluate,
            model_url=request.model_3d_url,
            prompt=request.prompt,
            user_id=request.user_id,
            reference_image=request.reference_image
        )
        
        return create_response(
            code=1,
            msg="3D模型评估任务已提交，将在后台执行",
            data={
                "model_3d_url": request.model_3d_url,
                "user_id": request.user_id,
                "status": "submitted",
                "submitted_at": datetime.now().isoformat()
            }
        )
        
    except Exception as e:
        logger.error(f"提交异步评估任务失败: {str(e)}")
        return create_response(
            code=0,
            msg=f"任务提交失败: {str(e)}",
            data={}
        )

# 获取评估报告列表接口
@router.get("/reports/user/{user_id}", tags=["评估报告管理"])
def get_user_reports(user_id: int, page: int = 1, page_size: int = 10):
    """
    获取用户的评估报告列表
    
    - **user_id**: 用户ID
    - **page**: 页码（从1开始）
    - **page_size**: 每页数量
    
    返回用户的评估报告列表
    """
    try:
        # 这里可以实现分页查询逻辑
        # 目前返回模拟数据
        logger.info(f"获取用户评估报告列表，用户ID: {user_id}, 页码: {page}")
        
        # 模拟数据
        mock_reports = [
            {
                "id": i + (page - 1) * page_size + 1,
                "title": f"3D模型评估报告 - 示例 {i + 1}",
                "model_3d_url": f"https://example.com/models/sample_{i + 1}.glb",
                "create_time": datetime.now().isoformat(),
                "read_status": 0,
                "overall_score": 8.5 + i * 0.1
            }
            for i in range(page_size)
        ]
        
        return create_response(
            code=1,
            msg="获取报告列表成功",
            data={
                "reports": mock_reports,
                "total": 100,  # 模拟总数
                "page": page,
                "page_size": page_size
            }
        )
        
    except Exception as e:
        logger.error(f"获取报告列表失败: {str(e)}")
        return create_response(
            code=0,
            msg=f"获取失败: {str(e)}",
            data={}
        )

# 获取单个评估报告详情接口
@router.get("/reports/{report_id}", tags=["评估报告管理"])
def get_report_detail(report_id: int):
    """
    获取单个评估报告的详细内容
    
    - **report_id**: 报告ID
    
    返回报告的完整内容
    """
    try:
        logger.info(f"获取评估报告详情，报告ID: {report_id}")
        
        # 模拟报告详情数据
        mock_report_detail = {
            "id": report_id,
            "title": "3D模型详细评估报告",
            "model_3d_url": "https://example.com/models/detailed_model.glb",
            "user_id": 1001,
            "markdown_report": "# 详细评估报告\n\n## 评估内容示例\n\n这是一个详细的3D模型评估报告示例。",
            "screenshot": "https://example.com/screenshots/model_preview.jpg",
            "read_status": 0,
            "create_time": datetime.now().isoformat()
        }
        
        # 构建返回数据
        report_data = {
            "title": mock_report_detail["title"],
            "markdown_report": mock_report_detail["markdown_report"]
        }
        
        return create_response(
            code=1,
            msg="获取报告详情成功",
            data=report_data
        )
        
    except Exception as e:
        logger.error(f"获取报告详情失败: {str(e)}")
        return create_response(
            code=0,
            msg=f"获取失败: {str(e)}",
            data={}
        )

# 标记报告为已读接口
@router.post("/reports/{report_id}/read", tags=["评估报告管理"])
def mark_report_as_read(report_id: int):
    """
    标记评估报告为已读状态
    
    - **report_id**: 报告ID
    
    返回操作结果
    """
    try:
        logger.info(f"标记报告为已读，报告ID: {report_id}")
        
        # 这里可以实现更新报告阅读状态的逻辑
        
        return create_response(
            code=1,
            msg="报告已标记为已读",
            data={"report_id": report_id, "read_status": 1}
        )
        
    except Exception as e:
        logger.error(f"标记报告为已读失败: {str(e)}")
        return create_response(
            code=0,
            msg=f"操作失败: {str(e)}",
            data={}
        )